Previous slide Next slide Toggle fullscreen Open presenter view
Программирование сетевых приложений
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Содержание лекции
Интерфейсы и абстрактные классы
Механизм перегрузки функций
Механизм виртуальных функций
Перегрузка операций языка
Создание множественных определений
Многоуровневая структурированная иерархия классов
Расширение интерфейсов
Полиморфизм в Qt6
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Полиморфизм как структурный механизм
Определение
Полиморфизм - это возможность использовать объекты разных типов единым образом, обеспечивая гибкость и расширяемость программ.
Типы полиморфизма
Статический (компиляционный) - перегрузка функций и операторов
Динамический (исполнительный) - виртуальные функции и наследование
Параметрический - шаблоны и обобщения
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Интерфейсы в C++
class INetworkProtocol {
public :
virtual ~INetworkProtocol () = default ;
virtual void connect (const string& address, int port) = 0 ;
virtual void disconnect () = 0 ;
virtual void sendData (const string& data) = 0 ;
virtual string receiveData () = 0 ;
virtual bool isConnected () const = 0 ;
};
class IEncryption {
public :
virtual ~IEncryption () = default ;
virtual string encrypt (const string& data) = 0 ;
virtual string decrypt (const string& data) = 0 ;
virtual string getAlgorithmName () const = 0 ;
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Реализация интерфейсов
class TcpProtocol : public INetworkProtocol {
private :
bool connected;
string serverAddress;
int serverPort;
public :
TcpProtocol () : connected (false ), serverPort (0 ) {}
void connect (const string& address, int port) override {
serverAddress = address;
serverPort = port;
connected = true ;
cout << "TCP connection established to " << address << ":" << port << endl;
}
void disconnect () override {
connected = false ;
cout << "TCP connection closed" << endl;
}
void sendData (const string& data) override {
if (connected) {
cout << "TCP sending: " << data << endl;
}
}
string receiveData () override {
return connected ? "TCP data received" : "" ;
}
bool isConnected () const override {
return connected;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Абстрактные классы и чисто виртуальные методы
class NetworkDevice {
protected :
string deviceId;
string manufacturer;
bool isActive;
public :
NetworkDevice (const string& id, const string& maker)
: deviceId (id), manufacturer (maker), isActive (false ) {}
virtual ~NetworkDevice () = default ;
virtual void configure () = 0 ;
virtual void start () = 0 ;
virtual void stop () = 0 ;
virtual string getDeviceInfo () const {
return "Device: " + deviceId + " by " + manufacturer;
}
void activate () { isActive = true ; }
void deactivate () { isActive = false ; }
bool getStatus () const { return isActive; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Конкретные реализации абстрактных классов
class Router : public NetworkDevice {
private :
int portCount;
vector<string> routingTable;
public :
Router (const string& id, const string& maker, int ports)
: NetworkDevice (id, maker), portCount (ports) {}
void configure () override {
cout << "Configuring router with " << portCount << " ports" << endl;
}
void start () override {
cout << "Starting router " << deviceId << endl;
isActive = true ;
}
void stop () override {
cout << "Stopping router " << deviceId << endl;
isActive = false ;
}
void addRoute (const string& destination) {
routingTable.push_back (destination);
}
};
class Switch : public NetworkDevice {
private :
int portCount;
bool managed;
public :
Switch (const string& id, const string& maker, int ports, bool isManaged)
: NetworkDevice (id, maker), portCount (ports), managed (isManaged) {}
void configure () override {
cout << "Configuring " << (managed ? "managed" : "unmanaged" )
<< " switch with " << portCount << " ports" << endl;
}
void start () override {
cout << "Starting switch " << deviceId << endl;
isActive = true ;
}
void stop () override {
cout << "Stopping switch " << deviceId << endl;
isActive = false ;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Перегрузка функций
class NetworkService {
public :
void connect () {
cout << "Connecting to default server" << endl;
}
void connect (const string& server) {
cout << "Connecting to server: " << server << endl;
}
void connect (const string& server, int port) {
cout << "Connecting to " << server << ":" << port << endl;
}
void sendData (const string& data) {
cout << "Sending string data: " << data << endl;
}
void sendData (const vector<char >& data) {
cout << "Sending binary data, size: " << data.size () << " bytes" << endl;
}
void sendData (int command) {
cout << "Sending command: " << command << endl;
}
void processData () { cout << "Non-const processing" << endl; }
void processData () const { cout << "Const processing" << endl; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Перегрузка операторов
class IPAddress {
private :
string address;
int subnetMask;
public :
IPAddress (const string& addr, int mask = 24 ) : address (addr), subnetMask (mask) {}
bool operator ==(const IPAddress& other) const {
return address == other.address && subnetMask == other.subnetMask;
}
bool operator !=(const IPAddress& other) const {
return !(*this == other);
}
IPAddress& operator =(const IPAddress& other) {
if (this != &other) {
address = other.address;
subnetMask = other.subnetMask;
}
return *this ;
}
IPAddress operator +(const IPAddress& other) const {
return IPAddress (address + "." + other.address, subnetMask);
}
friend ostream& operator <<(ostream& os, const IPAddress& ip) {
os << ip.address << "/" << ip.subnetMask;
return os;
}
string operator [](int index) const {
vector<string> octets = split (address, '.' );
return (index >= 0 && index < octets.size ()) ? octets[index] : "" ;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Виртуальные функции и динамический полиморфизм
class NetworkProtocol {
public :
virtual ~NetworkProtocol () = default ;
virtual void establishConnection (const string& address, int port) {
cout << "Basic connection establishment" << endl;
}
virtual void transmit (const string& data) {
cout << "Basic data transmission" << endl;
}
virtual string receive () {
return "Basic data reception" ;
}
virtual string getProtocolName () const = 0 ;
virtual void closeConnection () {
cout << "Basic connection closure" << endl;
}
};
class HTTPProtocol : public NetworkProtocol {
public :
void establishConnection (const string& address, int port) override {
cout << "Establishing HTTP connection to " << address << ":" << port << endl;
}
void transmit (const string& data) override {
cout << "Sending HTTP request: " << data << endl;
}
string receive () override {
return "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html>...</html>" ;
}
string getProtocolName () const override {
return "HTTP" ;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Использование виртуальных функций
class FTPProtocol : public NetworkProtocol {
public :
void establishConnection (const string& address, int port) override {
cout << "Establishing FTP connection with authentication" << endl;
}
void transmit (const string& data) override {
cout << "Sending FTP command: " << data << endl;
}
string receive () override {
return "FTP response: 226 Transfer complete" ;
}
string getProtocolName () const override {
return "FTP" ;
}
void closeConnection () override {
cout << "FTP connection closed, logout completed" << endl;
}
};
void transferFile (NetworkProtocol* protocol, const string& filename) {
cout << "Using protocol: " << protocol->getProtocolName () << endl;
protocol->establishConnection ("server.example.com" , 80 );
protocol->transmit ("GET " + filename);
string response = protocol->receive ();
cout << "Response: " << response << endl;
protocol->closeConnection ();
}
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Множественные определения через перегрузку
class DataProcessor {
public :
string process (const string& data) {
return "Processed string: " + data;
}
int process (int number) {
return number * 2 ;
}
vector<int > process (const vector<int >& data) {
vector<int > result;
for (int val : data) {
result.push_back (val * val);
}
return result;
}
NetworkPacket process (const NetworkPacket& packet) {
NetworkPacket processed = packet;
processed.timestamp = time (nullptr );
processed.isValid = true ;
return processed;
}
string process (const string& data, const string& encoding) {
return "Processed with " + encoding + ": " + data;
}
string process (const string& data, bool encrypt) {
return encrypt ? "Encrypted: " + data : "Plain: " + data;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Многоуровневая иерархия классов
class NetworkDevice {
protected :
string deviceId;
bool isActive;
public :
NetworkDevice (const string& id) : deviceId (id), isActive (false ) {}
virtual ~NetworkDevice () = default ;
virtual void start () = 0 ;
virtual void stop () = 0 ;
virtual string getDeviceType () const = 0 ;
void activate () { isActive = true ; }
void deactivate () { isActive = false ; }
};
class IPDevice : public NetworkDevice {
protected :
string ipAddress;
string subnetMask;
public :
IPDevice (const string& id, const string& ip)
: NetworkDevice (id), ipAddress (ip), subnetMask ("255.255.255.0" ) {}
virtual void configureIP (const string& ip, const string& mask) {
ipAddress = ip;
subnetMask = mask;
}
string getIPAddress () const { return ipAddress; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Продолжение многоуровневой иерархии
class Router : public IPDevice {
protected :
vector<string> routingTable;
int interfaceCount;
public :
Router (const string& id, const string& ip, int interfaces)
: IPDevice (id, ip), interfaceCount (interfaces) {}
void start () override {
cout << "Starting router " << deviceId << " with " << interfaceCount << " interfaces" << endl;
activate ();
}
void stop () override {
cout << "Stopping router " << deviceId << endl;
deactivate ();
}
string getDeviceType () const override {
return "Router" ;
}
void addRoute (const string& network, const string& gateway) {
routingTable.push_back (network + " -> " + gateway);
cout << "Route added: " << network << " via " << gateway << endl;
}
void configureIP (const string& ip, const string& mask) override {
IPDevice::configureIP (ip, mask);
cout << "Router IP configured: " << ip << "/" << mask << endl;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Расширение интерфейсов
class INetworkService {
public :
virtual ~INetworkService () = default ;
virtual void start () = 0 ;
virtual void stop () = 0 ;
virtual string getServiceName () const = 0 ;
};
class IConfigurableService : public INetworkService {
public :
virtual ~IConfigurableService () = default ;
virtual void loadConfiguration (const string& configFile) = 0 ;
virtual void saveConfiguration (const string& configFile) = 0 ;
virtual bool validateConfiguration () const = 0 ;
};
class IMonitoredService : public INetworkService {
public :
virtual ~IMonitoredService () = default ;
virtual ServiceStatus getStatus () const = 0 ;
virtual vector<string> getLog () const = 0 ;
virtual void clearLog () = 0 ;
virtual int getErrorCount () const = 0 ;
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Комбинирование интерфейсов
class WebServer : public IConfigurableService, public IMonitoredService {
private :
bool isRunning;
string configFile;
vector<string> logs;
int errorCount;
ServiceStatus status;
public :
WebServer () : isRunning (false ), errorCount (0 ), status (ServiceStatus::STOPPED) {}
void start () override {
if (validateConfiguration ()) {
isRunning = true ;
status = ServiceStatus::RUNNING;
log ("Web server started" );
} else {
log ("Failed to start: invalid configuration" );
errorCount++;
}
}
void stop () override {
isRunning = false ;
status = ServiceStatus::STOPPED;
log ("Web server stopped" );
}
string getServiceName () const override {
return "WebServer" ;
}
void loadConfiguration (const string& file) override {
configFile = file;
log ("Configuration loaded from " + file);
}
void saveConfiguration (const string& file) override {
log ("Configuration saved to " + file);
}
bool validateConfiguration () const override {
return !configFile.empty ();
}
ServiceStatus getStatus () const override {
return status;
}
vector<string> getLog () const override {
return logs;
}
void clearLog () override {
logs.clear ();
}
int getErrorCount () const override {
return errorCount;
}
private :
void log (const string& message) {
logs.push_back ("[" + getCurrentTime () + "] " + message);
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Полиморфизм в Qt6 - метаобъектная система
#include <QObject>
#include <QMetaObject>
#include <QMetaMethod>
class NetworkService : public QObject {
Q_OBJECT
public :
explicit NetworkService (QObject* parent = nullptr ) : QObject(parent) { }
virtual void startService () {
qDebug () << "Starting basic network service" ;
emit serviceStarted () ;
}
virtual void stopService () {
qDebug () << "Stopping network service" ;
emit serviceStopped () ;
}
virtual QString getServiceType () const = 0 ;
signals:
void serviceStarted () ;
void serviceStopped () ;
void dataReceived (const QString& data) ;
void errorOccurred (const QString& error) ;
public slots:
virtual void processData (const QString& data) {
qDebug () << "Processing data:" << data;
emit dataReceived (data) ;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Qt6 - конкретные реализации
class HttpService : public NetworkService {
Q_OBJECT
public :
explicit HttpService (QObject* parent = nullptr ) : NetworkService(parent) { }
void startService () override {
qDebug () << "Starting HTTP service on port 80" ;
emit serviceStarted () ;
}
void stopService () override {
qDebug () << "Stopping HTTP service" ;
emit serviceStopped () ;
}
QString getServiceType () const override {
return "HTTP" ;
}
public slots:
void processData (const QString& data) override {
qDebug () << "Processing HTTP request:" << data;
QString response = "HTTP/1.1 200 OK\n\n" + data.toUpper ();
emit dataReceived (response) ;
}
};
class FtpService : public NetworkService {
Q_OBJECT
public :
explicit FtpService (QObject* parent = nullptr ) : NetworkService(parent) { }
void startService () override {
qDebug () << "Starting FTP service on port 21" ;
emit serviceStarted () ;
}
QString getServiceType () const override {
return "FTP" ;
}
public slots:
void processData (const QString& data) override {
qDebug () << "Processing FTP command:" << data;
emit dataReceived ("226 Transfer complete" ) ;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Qt6 - использование полиморфизма с сигналами и слотами
class ServiceManager : public QObject {
Q_OBJECT
private :
QList<NetworkService*> services;
public :
ServiceManager (QObject* parent = nullptr ) : QObject (parent) {}
void addService (NetworkService* service) {
services.append (service);
connect (service, &NetworkService::serviceStarted,
this , &ServiceManager::onServiceStarted);
connect (service, &NetworkService::dataReceived,
this , &ServiceManager::onDataReceived);
connect (service, &NetworkService::errorOccurred,
this , &ServiceManager::onErrorOccurred);
}
void startAllServices () {
for (NetworkService* service : services) {
service->startService ();
}
}
void processDataForAll (const QString& data) {
for (NetworkService* service : services) {
service->processData (data);
}
}
public slots:
void onServiceStarted () {
NetworkService* service = qobject_cast <NetworkService*>(sender ());
if (service) {
qDebug () << "Service started:" << service->getServiceType ();
}
}
void onDataReceived (const QString& data) {
NetworkService* service = qobject_cast <NetworkService*>(sender ());
if (service) {
qDebug () << "Data from" << service->getServiceType () << ":" << data;
}
}
void onErrorOccurred (const QString& error) {
qDebug () << "Error:" << error;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Qt6 - свойства и динамическое поведение
class ConfigurableService : public NetworkService {
Q_OBJECT
Q_PROPERTY (QString configFile READ configFile WRITE setConfigFile)
Q_PROPERTY (bool autoStart READ autoStart WRITE setAutoStart)
Q_PROPERTY (int maxConnections READ maxConnections WRITE setMaxConnections)
private :
QString m_configFile;
bool m_autoStart;
int m_maxConnections;
public :
explicit ConfigurableService (QObject* parent = nullptr )
: NetworkService(parent), m_autoStart(false), m_maxConnections(100 ) { }
QString configFile () const { return m_configFile; }
void setConfigFile (const QString& file) { m_configFile = file; }
bool autoStart () const { return m_autoStart; }
void setAutoStart (bool autoStart) { m_autoStart = autoStart; }
int maxConnections () const { return m_maxConnections; }
void setMaxConnections (int max) { m_maxConnections = max; }
void startService () override {
if (!m_configFile.isEmpty ()) {
loadConfiguration (m_configFile);
}
qDebug () << "Starting configurable service with max connections:" << m_maxConnections;
emit serviceStarted () ;
}
QString getServiceType () const override {
return "Configurable" ;
}
private :
void loadConfiguration (const QString& file) {
qDebug () << "Loading configuration from:" << file;
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Примеры использования полиморфизма в сетевом программировании
class NetworkPacket {
public :
virtual ~NetworkPacket () = default ;
virtual string getType () const = 0 ;
virtual string serialize () const = 0 ;
virtual void deserialize (const string& data) = 0 ;
virtual size_t getSize () const = 0 ;
};
class TCPPacket : public NetworkPacket {
private :
string sourceIP;
string destIP;
int sourcePort;
int destPort;
string payload;
public :
string getType () const override { return "TCP" ; }
string serialize () const override {
return sourceIP + ":" + to_string (sourcePort) + " -> " +
destIP + ":" + to_string (destPort) + " " + payload;
}
void deserialize (const string& data) override {
size_t pos = data.find (" -> " );
if (pos != string::npos) {
string src = data.substr (0 , pos);
string rest = data.substr (pos + 4 );
}
}
size_t getSize () const override {
return sizeof (sourcePort) + sizeof (destPort) +
sourceIP.length () + destIP.length () + payload.length ();
}
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Паттерн "Фабрика" для создания полиморфных объектов
class PacketFactory {
public :
static unique_ptr<NetworkPacket> createPacket (const string& type) {
if (type == "TCP" ) {
return make_unique <TCPPacket>();
} else if (type == "UDP" ) {
return make_unique <UDPPacket>();
} else if (type == "HTTP" ) {
return make_unique <HTTPPacket>();
} else if (type == "FTP" ) {
return make_unique <FTPPacket>();
}
return nullptr ;
}
static vector<unique_ptr<NetworkPacket>> createPacketBatch (const vector<string>& types) {
vector<unique_ptr<NetworkPacket>> packets;
for (const auto & type : types) {
auto packet = createPacket (type);
if (packet) {
packets.push_back (move (packet));
}
}
return packets;
}
};
void processNetworkTraffic (const vector<string>& packetTypes) {
auto packets = PacketFactory::createPacketBatch (packetTypes);
for (const auto & packet : packets) {
cout << "Processing " << packet->getType () << " packet" << endl;
cout << "Size: " << packet->getSize () << " bytes" << endl;
}
}
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Преимущества использования структурных механизмов полиморфизма
Гибкость и расширяемость
Возможность добавлять новые типы без изменения существующего кода
Единый интерфейс для различных реализаций
Повторное использование кода
Базовые классы содержат общую функциональность
Наследование позволяет переиспользовать код
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Упрощение сопровождения
Изменения в базовом классе автоматически распространяются на наследников
Четкое разделение интерфейса и реализации
Типобезопасность
Компилятор проверяет соответствие типов
Виртуальные функции обеспечивают безопасное приведение типов
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Рекомендации по использованию полиморфизма
1. Проектирование интерфейсов
Интерфейсы должны быть минимальными и специфичными
Используйте принцип разделения интерфейсов (ISP)
2. Использование виртуальных функций
Делайте деструкторы виртуальными в базовых классах
Используйте override для явного указания переопределения
3. Перегрузка функций
Избегайте неоднозначных перегрузок
Документируйте различия между перегруженными версиями
4. Управление памятью
Используйте умные указатели для полиморфных объектов
Помните о правиле трех/пяти/нуля
5. Производительность
Статический полиморфизм (шаблоны) может быть быстрее динамического
Виртуальные функции имеют небольшую накладные расходы
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Заключение
Основные структурные механизмы полиморфизма:
Интерфейсы и абстрактные классы - определение контрактов
Виртуальные функции - динамическая диспетчеризация
Перегрузка функций - статический полиморфизм
Перегрузка операторов - расширение возможностей типов
Множественное наследование - комбинирование функциональности
Шаблоны - параметрический полиморфизм
Применение в сетевом программировании:
Унификация работы с различными протоколами
Гибкая архитектура сетевых приложений
Расширяемость и сопровождаемость кода
Интеграция с Qt6 через метаобъектную систему
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений
Вопросы для самопроверки
Чем отличаются интерфейсы от абстрактных классов в C++?
Какие типы полиморфизма существуют и как они реализуются?
Когда использовать виртуальные функции, а когда перегрузку?
Как реализовать множественные определения для одной функции?
Что такое чисто виртуальные методы и зачем они нужны?
Как работает динамическая диспетчеризация методов?
Какие преимущества дает использование полиморфизма в сетевом программировании?
Как реализовать полиморфизм в Qt6 с использованием сигналов и слотов?
Структурные механизмы языка программирования для реализации полиморфизма в программах
Заметки докладчика:
- Полиморфизм — одна из важнейших тем для сетевого программирования. Он позволяет писать код, не зависящий от конкретного протокола: через общий интерфейс можно работать с TCP, UDP, WebSocket и другими протоколами единообразно.
- Обратите внимание: при проектировании сетевых приложений полиморфизм используется повсеместно — от обработки пакетов до реализации подключаемых модулей шифрования.
Заметки докладчика:
- В C++ нет ключевого слова «interface» как в Java. Интерфейс в C++ — это класс, содержащий только чисто виртуальные методы (с = 0) и не имеющий полей данных.
- Принятое соглашение: префикс «I» в имени (IConnectable, ISerializable, INetworkProtocol).
- Деструктор интерфейса всегда должен быть виртуальным (virtual ~IName() = default), иначе при удалении через указатель на интерфейс не будет вызван деструктор производного класса.
Заметки докладчика:
- Перегрузка (overload) разрешается на этапе компиляции — это статический полиморфизм. Не путайте с переопределением (override), которое работает в runtime.
- Overload: одинаковое имя, разные параметры (количество или типы).
- Override: совпадающая сигнатура в производном классе, вызов через vtable.
- В сетевом программировании перегрузка удобна для API, принимающих разные форматы данных (строка, бинарный буфер, команда).
Заметки докладчика:
- Перегружайте операторы только тогда, когда их смысл естественен и очевиден (== для сравнения, << для вывода, [] для индексации).
- Всегда реализуйте перегрузку через открытый интерфейс класса, а не через внутренние поля.
- Помните о правиле трёх/пяти: если перегружаете оператор присваивания, вероятно, нужны также деструктор и конструктор копирования (или перемещения).
Заметки докладчика:
- Накладные расходы vtable: один указатель на объект (8 байт на 64-битной системе) + один косвенный вызов на каждый виртуальный метод.
- Обычно это незначительно, но в критичных к производительности циклах (например, обработка тысяч пакетов в секунду) может иметь значение.
- Используйте ключевое слово `final` для классов и методов, чтобы позволить компилятору выполнить девиртуализацию (devirtualization) — заменить косвенный вызов на прямой.
Заметки докладчика:
- Паттерн «Фабрика» широко применяется в сетевом программировании для создания обработчиков протоколов. Пример: PacketFactory создаёт TCPPacket, UDPPacket на основе заголовка пакета.
- Это позволяет добавлять новые протоколы без изменения клиентского кода — принцип открытости/закрытости (Open/Closed principle из SOLID).
- В реальных проектах часто используют реестр: каждый протокол сам регистрирует свою фабричную функцию, что полностью устраняет необходимость модифицировать PacketFactory при добавлении нового типа.
Заметки докладчика:
Ожидаемые ответы:
1. Интерфейс — класс только с чисто виртуальными методами и без полей данных. Абстрактный класс может иметь поля, обычные и виртуальные методы с реализацией по умолчанию.
2. Статический (перегрузка, шаблоны — на этапе компиляции), динамический (виртуальные функции — в runtime), параметрический (шаблоны/обобщения).
3. Виртуальные функции — когда поведение зависит от реального типа объекта в runtime. Перегрузку — когда нужно одинаковое имя для операций с разными параметрами, выбор на этапе компиляции.
4. Определить несколько функций с одним именем, но разными списками параметров (разное количество, типы или модификаторы const).
5. Метод с "= 0" — не имеет реализации в базовом классе, делает класс абстрактным. Производный класс обязан его переопределить.
6. Через таблицу виртуальных функций (vtable) — указатель на vtable хранится в каждом объекте, вызов происходит через косвенную адресацию.
7. Единый интерфейс для разных протоколов (TCP/UDP/WebSocket), расширяемость без изменения существующего кода, упрощение тестирования (моки через интерфейсы).
8. Наследовать от QObject, использовать Q_OBJECT, объявлять виртуальные слоты в базовом классе и переопределять их в производных, связывать сигналы со слотами через connect().